/*
 * utility.cpp
 *
 *  Created on: 2009-1-13
 *      Author: fanliangliang
 */

#include "utility.h"
#include "regex.h"
#include "toxic.h"
#include <utility> // for pair

using namespace toxic;
using namespace std;

bool isDirectory(const string& pathname) {
	struct stat st;
	if (stat(pathname.c_str(), &st) < 0) {
		return false;
	}
	return S_ISDIR(st.st_mode);
}

static void traverse_directory(const file_info& fi, void* arg) {
	vector<string>* result = static_cast<vector<string>*>(arg);
	if (!fi.is_dir()) {
		result->push_back(fi.pathname);
	}
}

void traverseDirectory(vector<string>& result, const string& pathname, size_t depth) {
	traverse_file(pathname.c_str(), traverse_directory, &result, depth);
}


typedef pair<vector<string>*, const string*> ResultPatternPair;

static void traverse_directory_with_pattern(const file_info& fi, void* arg) {
	ResultPatternPair* rp = static_cast<ResultPatternPair*>(arg);
	if (wildcard_match(rp->second->c_str(), toxic::basename(fi.pathname).c_str())) {
		rp->first->push_back(fi.pathname);
	}
}

void traverseDirectoryWithPattern(vector<string>& result, const string& pattern, const string& pathname, size_t depth) {
	ResultPatternPair rp(&result, &pattern);
	traverse_file(pathname.c_str(), traverse_directory_with_pattern, &rp, depth);
}

static size_t getRegularFileSize(const char* pathname) {
	ifstream in(pathname, ios::ate | ios::binary);
	return in ? size_t(in.tellg()) : size_t(0);
}

static void get_file_size(const file_info& fi, void* arg) {
	size_t* size = static_cast<size_t*>(arg);
	if (!fi.is_dir()) {
		*size += getRegularFileSize(fi.pathname);
	}
}

size_t getFileSize(const string& pathname) {
	size_t size = 0;
	traverse_file(pathname.c_str(), get_file_size, &size);
	return size;
}

typedef pair<size_t*, const string*> SizeStringPair;

static void get_file_size_with_pattern(const file_info& fi, void* arg) {
	SizeStringPair* ss = static_cast<SizeStringPair*>(arg);
	if (wildcard_match(ss->second->c_str(), toxic::basename(fi.pathname).c_str())) {
		size_t temp = getFileSize(fi.pathname);
		//xtrace << "sizeof {" << fi.pathname << "} = {" << temp << "} bytes";
		*ss->first += temp;
	}
}

size_t getFileSizeWithPattern(const string& pathname, const string& pattern) {
	size_t size = 0;
	SizeStringPair ss(&size, &pattern);
	traverse_file(pathname.c_str(), get_file_size_with_pattern, &ss, 1);
	return size;
}

static void get_file_size_with_pattern_ex(const file_info& fi, void* arg) {
	SizeStringPair* ss = static_cast<SizeStringPair*>(arg);
	if (!fi.is_dir()) {
		if (wildcard_match(ss->second->c_str(), toxic::basename(fi.pathname).c_str())) {
			size_t temp = getRegularFileSize(fi.pathname);
			//xtrace << "sizeof {" << fi.pathname << "} = {" << temp << "} bytes";
			*ss->first += temp;
		}
	}
}

size_t getFileSizeWithPatternEx(const string& pathname, const string& pattern) {
	size_t size = 0;
	SizeStringPair ss(&size, &pattern);
	traverse_file(pathname.c_str(), get_file_size_with_pattern_ex, &ss);
	return size;
}

static bool execute(const string& cmd) {
	if (system(cmd.c_str()) != 0) {
		xerror << "execute command {" << cmd << "} failed {" << errno
			<< ":" << strerror(errno) << "}.";

		return false;
	}

	xtrace << "execute command {" << cmd << "} successfully";
	return true;
}

bool deleteFile(const string& _pathname) {
	string pathname(_pathname);
#if defined(PLATFORM_WIN32)
	toxic::replace(pathname, '/', '\\');
	string cmd = "del /Q \"" + pathname + "\"";
#else
	string cmd = "rm -f \"" + pathname + "\"";
#endif
	if (!execute(cmd)) {
		xwarn << "can't delete {" + pathname + "}";
		return false;
	}
	else {
		xtrace << "delete {" + pathname + "} successfully";
		return true;
	}
}

string getCurrentDirectory() {
	char buffer[MAX_PATH] = { 0 };
	if (GetCurrentDirectory(sizeof(buffer), buffer) == 0) {
		return string();
	}
	else {
		return string(buffer);
	}
}
